﻿<!DOCTYPE html>
<html>
<head>
	<title>各种循环比较</title>
	<style type="text/css"> 
		body{font-family:helvetica,arial,sans-serif;font-size:12px;}
		span{display:none;}
		table{border-collapse:collapse;margin:10px 0px;}
		caption{text-align:left;font-size:18px;font-weight:bold;margin:10px 0px;}
		td{padding:10px;border:2px solid #ccc;}
		td.bench{color:#c60;font-weight:normal;}
		td.code{font-family:"courier new",monospace;}
	</style> 
	<script type="text/javascript">

		var chars = '0123456789abcdef';

		function getRandomString() {
			var len = Math.ceil(Math.random() * 7) + 3; // 4-10
			var result = "";
			while (len--) {
				result += chars.charAt(Math.floor(Math.random() * chars.length));
			}
			return result;
		}

		function createDummySpans(howMany) {
			for (var i = 0; i < howMany; i++) {
				var span = document.createElement('span');
				span.innerHTML = ' ' + getRandomString() + ' ';
				document.body.appendChild(span);
			}
		}

		function esc(str) {
			str = str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
			return str;
		}

		var forEachImp = 'native';
		if (!Array.prototype.forEach) {
			forEachImp = 'custom';
			Array.prototype.forEach = function (fun) {
				var len = this.length;
				if (typeof fun != "function") { throw new TypeError(); }
				var thisp = arguments[1];
				for (var i = 0; i < len; i++) {
					if (i in this) { fun.call(thisp, this[i], i, this); }
				}
			};
		}

		function test() {
			document.getElementById('h').firstChild.data = 'Testing...';
			document.getElementById('h').style.color = '#c60';

			var size = 1000;
			var mult = 100;

			var arr = [];
			var lsize = size;
			while (lsize--) { arr.push('' + getRandomString() + ''); }

			var sarr = [];
			var lsize = size;
			var which_i = 0;
			while (lsize--) {
				var skip_ahead = 0;
				if (Math.random() > 0.4) {
					skip_ahead = Math.ceil(Math.random() * 10);
				} else if (Math.random() > 0.2) {
					skip_ahead = Math.ceil(Math.random() * 50);
				}
				which_i += skip_ahead;
				sarr[which_i] = '' + getRandomString() + '';
			}

			createDummySpans(size);
			var hColl = document.getElementsByTagName('span');

			var start = {};
			var end = {};
			var comment = {};
			var testDesc;
			var result = "";

			//#########################################

			testDesc = "for (var i=0; i<arr.length; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0; i < arr.length; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '普通for循环';

			//#########################################

			testDesc = "for (var i=0, len=arr.length; i<len; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, len = arr.length; i < len; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for循环，但预先缓存length属性';

			//#########################################

			testDesc = "var i = 0; while (i < arr.length) { i++; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = 0; while (i < arr.length) { i++; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '普通while循环';

			//#########################################

			testDesc = "var i = 0, len = arr.length; while (i < len) { i++; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = 0, len = arr.length; while (i < len) { i++; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'while循环，但预先缓存length属性';

			//#########################################

			testDesc = "var i = arr.length; while (i--) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = arr.length; while (i--) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '倒序while循环';

			//#########################################

			testDesc = "var i = arr.length-1; do {  } while (i--);";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = arr.length - 1; do { } while (i--);
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'do ... while循环';

			//#########################################

			testDesc = "for (var i=arr.length; i--;) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = arr.length; i--; ) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '倒序for循环';

			//#########################################

			var popArrs = [];
			for (var i = 0; i < mult; i++) { popArrs.push(arr.slice()); }
			testDesc = "var x; while (x = arr.pop()) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var x; while (x = popArrs[a].pop()) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '通过pop方法驱动while循环(但可能会在稀疏数组中出错).';

			//#########################################

			testDesc = "for (var i in arr) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i in arr) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for...in循环（但可能会遍历更多东西）';

			//#########################################

			testDesc = "var isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/; for (var i in arr) { if(!isInt.test(i)){continue;} }";
			start[testDesc] = new Date().getTime();
			var isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
			for (var a = 0; a < mult; a++) {
				for (var i in arr) { if (!isInt.test(i)) { continue; } }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for...in循环并进行isInt检测';

			//#########################################

			testDesc = "for (var i=0; arr[i]; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0; arr[i]; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for循环，利用元素的自动转换进行中断循环（但如果某个元素为零……）.';

			//#########################################

			testDesc = "for (var i=0; arr[i]; i++) { var x = arr[i]; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0; arr[i]; i++) { var x = arr[i]; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '同上，并增加更多检测';

			//#########################################

			testDesc = "for (var i=0, x; x = arr[i++];) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, x; x = arr[i++]; ) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '同上，合并当中两个步骤.';

			//#########################################

			testDesc = "for (var i=0, len=arr.length; < len; i++) { var x = arr[i]; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, len = arr.length; i < len; i++) { var x = arr[i]; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '普通循环，并在循环增加引用';

			//#########################################

			testDesc = "arr.forEach(function(x){});";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				arr.forEach(function (x) { });
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = forEachImp + ' forEach循环';

			//#########################################

			testDesc = "var f=function(x){}; for (var i=0, len=arr.length; i<len; i++) { f(arr[i]); }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var f = function (x) { }; for (var i = 0, len = arr.length; i < len; i++) { f(arr[i]); }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '用for循环模拟forEach';

			//#########################################

			result += '<table class="data">';
			result += '<caption>原生数组对象 (length=' + arr.length + ', looped ' + mult + ' times)</caption>';
			for (var testDesc in start) {
				result += '<tr>';
				result += '<td class="comment">' + comment[testDesc] + '</td>';
				result += '<td class="code">' + esc(testDesc) + '</td>';
				result += '<td class="bench">' + (end[testDesc] - start[testDesc]) + 'ms</td>';
				result += '</tr>';
			}
			result += '</table>';

			var start = {};
			var end = {};
			var comment = {};

			//#########################################

			testDesc = "for (var i=0; i<sarr.length; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0; i < sarr.length; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '普通for循环';

			//#########################################

			testDesc = "for (var i=0, len=sarr.length; i<len; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, len = sarr.length; i < len; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for循环，但预先缓存length属性';

			//#########################################

			testDesc = "var i = 0; while (i < sarr.length) { i++; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = 0; while (i < sarr.length) { i++; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '普通while循环';

			//#########################################

			testDesc = "var i = 0, len = sarr.length; while (i < len) { i++; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = 0, len = sarr.length; while (i < len) { i++; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'while循环，但预先缓存length属性';

			//#########################################

			testDesc = "var i = sarr.length; while (i--) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = sarr.length; while (i--) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '倒序while循环';

			//#########################################

			testDesc = "var i = sarr.length-1; do {  } while (i--);";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = sarr.length - 1; do { } while (i--);
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'do ... while循环';

			//#########################################

			testDesc = "for (var i=sarr.length; i--;) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = sarr.length; i--; ) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '倒序for循环';

			//#########################################

			testDesc = "for (var i in sarr) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i in sarr) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for...in循环';

			//#########################################

			testDesc = "var isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/; for (var i in sarr) { if(!isInt.test(i)){continue;} }";
			start[testDesc] = new Date().getTime();
			var isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
			for (var a = 0; a < mult; a++) {
				for (var i in sarr) { if (!isInt.test(i)) { continue; } }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for...in循环并进行isInt检测';

			//#########################################

			testDesc = "sarr.forEach(function(x){});";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				sarr.forEach(function (x) { });
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = forEachImp + 'Array.forEach() ';

			//#########################################

			testDesc = "var f=function(x){}; for (var i=0, len=sarr.length; i<len; i++) { f(sarr[i]); }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var f = function (x) { }; for (var i = 0, len = sarr.length; i < len; i++) { f(sarr[i]); }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '用for循环模拟forEach';

			//#########################################

			result += '<table class="data">';
			result += '<caption>稀疏数组对象 (length=' + sarr.length + ', sporadically populated with ' + size + ' items, looped ' + mult + ' times)</caption>';
			for (var testDesc in start) {
				result += '<tr>';
				result += '<td class="comment">' + comment[testDesc] + '</td>';
				result += '<td class="code">' + esc(testDesc) + '</td>';
				result += '<td class="bench">' + (end[testDesc] - start[testDesc]) + 'ms</td>';
				result += '</tr>';
			}
			result += '</table>';

			var start = {};
			var end = {};
			var comment = {};

			//#########################################

			testDesc = "for (var i=0; i<hColl.length; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0; i < hColl.length; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '普通for循环';

			//#########################################

			testDesc = "for (var i=0, len=hColl.length; i<len; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, len = hColl.length; i < len; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for循环，但预先缓存length属性';

			//#########################################

			testDesc = "var i = 0; while (i < hColl.length) { i++; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = 0; while (i < hColl.length) { i++; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '普通while循环';

			//#########################################

			testDesc = "var i = 0, len = hColl.length; while (i < len) { i++; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = 0, len = hColl.length; while (i < len) { i++; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'while循环，但预先缓存length属性';

			//#########################################

			testDesc = "var i = hColl.length; while (i--) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = hColl.length; while (i--) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '倒序while循环';

			//#########################################

			testDesc = "var i = hColl.length-1; do {  } while (i--);";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				var i = hColl.length - 1; do { } while (i--);
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'do ... while循环';

			//#########################################

			testDesc = "for (var i=hColl.length; i--;) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = hColl.length; i--; ) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '倒序for循环';

			//#########################################

			testDesc = "for (var i in hColl) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i in hColl) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for...in循环';

			//#########################################

			testDesc = "var isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/; for (var i in hColl) { if(!isInt.test(i)){continue;} }";
			start[testDesc] = new Date().getTime();
			var isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
			for (var a = 0; a < mult; a++) {
				for (var i in hColl) { if (!isInt.test(i)) { continue; } }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for...in循环并进行isInt检测';

			//#########################################

			testDesc = "for (var i=0; hColl[i]; i++) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0; hColl[i]; i++) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for循环，通过自动转换元素来中断循环';

			//#########################################

			testDesc = "for (var i=0; hColl[i]; i++) { var x = hColl[i]; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0; hColl[i]; i++) { var x = hColl[i]; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '同上，并在循环中引用元素';

			//#########################################

			testDesc = "for (var i=0, x; x = hColl[i++];) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, x; x = hColl[i++]; ) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '同上，不过是利用引用中断循环';

			//#########################################

			testDesc = "for (var i=0, x; x = hColl.item(i++);) {  }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, x; x = hColl.item(i++); ) { }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = '同上，不过是通过item获取元素然后放到变量';

			//#########################################

			testDesc = "for (var i=0, len=hColl.length; i<len; i++) { var x = hColl[i]; }";
			start[testDesc] = new Date().getTime();
			for (var a = 0; a < mult; a++) {
				for (var i = 0, len = hColl.length; i < len; i++) { var x = hColl[i]; }
			}
			end[testDesc] = new Date().getTime();
			comment[testDesc] = 'for循环，在循环增加引用元素';

			//#########################################

			result += '<table class="data">';
			result += '<caption>HTML Collection对象 (length=' + hColl.length + ', looped ' + mult + ' times)</caption>';
			for (var testDesc in start) {
				result += '<tr>';
				result += '<td class="comment">' + comment[testDesc] + '</td>';
				result += '<td class="code">' + esc(testDesc) + '</td>';
				result += '<td class="bench">' + (end[testDesc] - start[testDesc]) + 'ms</td>';
				result += '</tr>';
			}
			result += '</table>';

			document.body.innerHTML += result;

			document.getElementById('h').firstChild.data = 'Done Testing.';
			document.getElementById('h').style.color = '#060';
		}

	</script>
</head>
<body>
	<h1 id="h">
		javascript循环测试程序</h1>
	<h2>
		<a href="#" onclick="this.style.display='none';test();return false;">开始测试</a></h2>
</body>
</html>
